package com.cd826dong.clouddemo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import rx.Observable;
import rx.Subscriber;

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixObservableCommand;

/**
 * @author ZHOUTIEQIANG053
 * Hystrix主要是通过HystrixCommand和HystrixObservableCommand
两个类来实现对服务的保护，那么这两个类有什么区别呢？
·从命令模式上来说，HystrixCommand是一个阻塞型命令，当执
行命令时可以直接获取到执行结果。而HystrixObservableCommand是
一个非阻塞型命令，该命令的调用者通过订阅其返回对象来获取执行
的结果。不过，HystrixCommand命令也提供了observe（）方法，可以
返回一个非阻塞型对象，但返回的Observable对象只能向调用者发送
一次数据。
·从代码编写上来说，HystrixCommand命令的业务逻辑写在
run（）方法中，服务降级逻辑写在getFallback（）方法中；而
HystrixObservableCommand的业务逻辑写在construct（）方法中，服务
降级逻辑写在resumeWithFallback（）方法中。
·从执行上来说，HystrixCommand的run（）是由新创建的线程执
行；而HystrixObservable Command的construct（）则是由调用程序线
程执行。
·从执行返回的结果来说，HystrixCommand只能返回一个执行结
果；而Hystrix ObservableCommand则可以按顺序向调用者发送多条执
行结果。
从前面的Hystrix执行流程图中可以看到，HystrixCommand和
HystrixObservable Command总共提供了execute（）、queue（）、
observe（）和toObservable（）4种命令执行方式，那么这4种命令执
行方式之间有什么联系和区别呢？
让我们先看一下这4种方式的区别。
·execute（）：该方法将以同步堵塞方式执行run（）。也就是说
当调用execute（）后，Hystrix将会首先创建一个新线程来运行
run（），同时调用者程序会在execute（）调用处一直处于堵塞状
态，直到run（）运行完成。
·queue（）：该方法将以异步非堵塞方式执行run（）。也就是说
当调用queue（）后，调用者线程就直接返回一个Future对象，同时
Hystrix创建一个新线程运行run（），调用者通过Future.get（）拿到
run（）的返回结果，而Future.get（）则是堵塞执行的。
·observe（）：执行该方法时，Hystrix会首先触发执行
HystrixCommand的run（）方法，或执行HystrixObservableCommand的
construct（）方法。对于HystrixCommand，将创建一个新线程以非堵
塞方式执行run（）；如果是HystrixObservableCommand，将在调用程
序线程堵塞执行construct（）。然后再调用subscribe（）完成事件注
册，如果run（）或construct（）执行成功则触发onNext（）和
onCompleted（）方法，如果执行异常则触发onError（）。
·toObservable（）：与observe（）不同的是，toObservable（）
方法是先注册，注册完成后自动触发并执行run（）或construct（）方
法。
在官方中称observe（）调用方式为热响应式调用（Hot
Observable），也就是说不论是否已经订阅，Hystrix都会立即执行该
命令。同时Hystrix会提供一种ReplaySubject方式进行过滤，所以不必
担心已经执行但是还没被订阅的命令执行结果会丢失。
对于toObservable（）的调用方式则称为冷响应式调用（Cold
Observable），也就是说直到订阅这个命令才会执行，否则要进行等
待。
 *
 */
public class HystrixObservableCommandFailureService extends HystrixObservableCommand<String> {

	private String name = "HystrixObservableCommand";
	private RestTemplate restTemplate;
	
	public HystrixObservableCommandFailureService(RestTemplate restTemplate, String name) {
		super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")));
		this.restTemplate = restTemplate;
		this.name = name;
	}


	@Override
	protected Observable<String> construct() {
		
		return Observable.create(new Observable.OnSubscribe<String>() {
	           @Override
	           public void call(Subscriber<? super String> subscriber) {
	               try {
	                   if(!subscriber.isUnsubscribed()) {
	                	   //这里取不到HystrixObservableCommandFailureService的全局变量？？是起了新线程执行方法的原因？
	                	   String result = restTemplate.getForEntity("http://127.0.0.1:2100/hello/{name}", String.class, name).getBody();
	                	   
	                       subscriber.onNext(String.valueOf(result));
	                       subscriber.onCompleted();
	                   }
	               } catch (Exception e) {
	                   subscriber.onError(e);
	               }
	           }

	       });
		
//		String result = restTemplate.getForEntity("http://127.0.0.1:2100/hello/{name}", String.class, name).getBody();
//		return Observable.just(result);
	}
	
	@Override
	protected Observable<String> resumeWithFallback() {
		return Observable.just("fall back use resumeWithFallback:" + name);
	}

}
